<?php
/**
 * APP授权Token
 * User: dxk <1024114660@qq.com>
 * Date: 2022/4/7
 */
namespace App\Service\OpenApi;

use App\Service\EasyRedis;

class AppAuthTokenService
{
    private $Redis;
    private $prefix = '';
    private $app_key = '';

    public function __construct($app_key)
    {
        $this->Redis = EasyRedis::getRedis();
        if ($app_key == 'admin') {
            $this->prefix = 'staff';
        } else {
            $this->prefix = 'user';
        }
        $this->app_key = trim($app_key);
    }

    /**
     * 获取token数据
     * @param $key
     * @return false|mixed
     * @throws \RedisException
     */
    public function getToken($key): mixed
    {
        if (empty($key)) {
            return false;
        }
        $res = $this->Redis->get($this->prefix . $key);
        return is_array(json_decode($res, true)) ? json_decode($res, true) : $res;
    }

    /**
     * 设置token数据
     * @param string $key
     * @param $token_data
     * @param $expire_time
     * @return bool|\Redis
     */
    private function setToken(string $key, $token_data, $expire_time = null)
    {
        if (empty($key) || empty($token_data)) {
            return false;
        }
        if (is_array($token_data)) {
            $token_data = json_encode($token_data);
        }
        if ($expire_time !== null) {
            return $this->Redis->setex($this->prefix . $key, $expire_time, $token_data);
        } else {
            return $this->Redis->set($this->prefix . $key, $token_data);
        }
    }

    /**
     * 删除token
     * @param $key
     * @return void
     */
    private function deleteToken($key): void
    {
        if (empty($key)) {
            return;
        }
        $this->Redis->del($this->prefix . $key);
    }

    /**
     * 生成授权token
     * @param string $operate_id token所属用户
     * @param int $expires_in 凭证有效时间，单位：秒
     * @param array $params 凭证对应的信息
     * @return array|bool
     */
    public function createAuthToken(string $operate_id, int $expires_in, array $params = []): bool|array
    {
        $user_key = 'USER:' . $operate_id;
        $old_access_token = $this->getToken($user_key);
        //删除旧的token
        if ($old_access_token) {
            $this->deleteToken('ACCESSTOKEN:' . $old_access_token);
        }
        //生成新的token
        $time = time();
        $auth_expire_at = $time + $expires_in;
        $access_token = strtoupper(md5(uniqid($operate_id) . $time));
        $res = $this->setToken($user_key, $access_token, $expires_in);
        if (!$res) {
            return false;
        }
        $token_data = [
            'access_token' => $access_token,
            'operate_id' => $operate_id,
            'app_key' => $this->app_key,
            'auth_at' => date('Y-m-d H:i:s'),  // 授权时间
            'auth_expire_at' => date('Y-m-d H:i:s', $auth_expire_at),  // 授权过期时间
            'params' => $params,
        ];
        $res = $this->setToken('ACCESSTOKEN:' . $access_token, $token_data, $expires_in);
        if ($res) {
            return $token_data;
        }
        return false;
    }

    /**
     * 刷新token
     * @param $operate_id
     * @param $access_token
     * @param $expires_in
     * @return array|false
     */
    public function refreshAuthToken($operate_id, $access_token, $expires_in)
    {
        $user_key = 'USER:' . $operate_id;
        $check_token = $this->getToken($user_key);
        if (!$check_token) {
            return false;
        }
        $time = time();
        $auth_expire_at = $time + $expires_in;
        $res = $this->setToken($user_key, $access_token, $expires_in);
        if (!$res) {
            return false;
        }
        $token_data = $this->getToken('ACCESSTOKEN:' . $access_token);
        if (is_array($token_data)) {
            $token_data['auth_expire_at'] = date('Y-m-d H:i:s', $auth_expire_at);
            $res = $this->setToken('ACCESSTOKEN:' . $access_token, $token_data, $expires_in);
            if ($res) {
                return $token_data;
            }
        }
        return false;
    }

    /**
     * 删除授权Token
     * @param $access_token
     * @return bool
     */
    public function deleteAuthToken($access_token): bool
    {
        $access_token = trim($access_token);
        $old_token = $this->getToken('ACCESSTOKEN:' . $access_token);
        if (empty($old_token)) {
            return true;
        }
        $this->deleteToken('ACCESSTOKEN:' . $access_token);
        return true;
    }
}
